#pragma once
#include "../buffer.hpp"

namespace opengl {

/* Constructors */
OPENGLAPI buffer::buffer() : id(0) {}
OPENGLAPI buffer::buffer(buffer &&other) : id(other.id) { other.id = 0; }
OPENGLAPI buffer::buffer(u64 size, const void *data, u32 flags) { create(size, data, flags); }
OPENGLAPI void buffer::create(u64 size, const void *data, u32 flags) {
    api::glCreateBuffers(1, &id);
    api::glNamedBufferStorage(id, size, data, flags);
}
OPENGLAPI buffer buffer::copy_from(const buffer &other) {
    buffer new_buffer;
    api::glCreateBuffers(1, &new_buffer.id);
    i32 size = 0, flags;
    api::glGetNamedBufferParameteriv(other.id, OPENGL_BUFFER_SIZE, &size);
    api::glGetNamedBufferParameteriv(other.id, OPENGL_BUFFER_FLAGS, &flags);
    if (size > 0) {
        api::glNamedBufferStorage(new_buffer.id, size, nullptr, flags);
        api::glCopyNamedBufferSubData(other.id, new_buffer.id, 0, 0, size);
    }
    return new_buffer;
}

/* Member functions */
OPENGLAPI void buffer::bind(u32 target) const { api::glBindBuffer(target, id); }
OPENGLAPI void buffer::bind_to(u32 target, u32 index) const { api::glBindBufferBase(target, index, id); }
OPENGLAPI void buffer::set_data(const void *data, u64 size, u64 offset) const {
    api::glNamedBufferSubData(id, offset, size, data);
}

/* Operator overloads */
OPENGLAPI buffer &buffer::operator=(buffer &&other) {
    if (this != &other) {
        if (id != 0) api::glDeleteBuffers(1, &id);
        id = other.id;
        other.id = 0;
    }
    return *this;
}

/* Destructor */
OPENGLAPI buffer::~buffer() {
    if (id != 0) api::glDeleteBuffers(1, &id);
}

} // namespace opengl